<?php

namespace app\model;

use support\Model;

/**
 * 核销码订单模型
 * 
 * 用于管理核销码订单相关数据
 * 包含订单ID、商品ID、核销码、手机号等信息
 * 
 * @property int $id 主键ID
 * @property int $order_id 订单ID
 * @property int $biz_goods_id 商家商品ID
 * @property string $code 核销码
 * @property string $phone 下单手机号
 * @property string $goods_name 商品名称
 * @property string $biz_name 商家名称
 * @property int $status 状态 0: 未使用, 1: 已使用, 2: 已过期
 * @property int|null $used_at 使用时间
 * @property int $created_at 创建时间
 * @property int $updated_at 更新时间
 */
class BizGoodsTicketModel extends Model
{
    /**
     * 关联表名
     * @var string
     */
    protected $table = 'biz_goods_ticket';

    /**
     * 主键
     * @var string
     */
    protected $primaryKey = 'id';

    /**
     * 关闭自动时间戳
     * @var bool
     */
    public $timestamps = false;

    /**
     * 可批量赋值字段
     * @var array
     */
    protected $fillable = [
        'order_id', 'biz_goods_id', 'code', 'phone', 'goods_name', 'biz_name', 'status', 'used_at'
    ];

    const STATUS_TEXT = [
        0 => '未使用',
        1 => '已使用',
        2 => '退款中',
        3 => '已退款'
    ];

    /**
     * 隐藏字段
     * @var array
     */
    protected $hidden = [
    ];

    /**
     * 追加字段
     * @var array
     */
    protected $appends = [
    ];

    protected $guarded = [];

    /**
     * 状态常量
     */
    const STATUS_UNUSED = 0;    // 未使用
    const STATUS_USED = 1;      // 已使用
    const STATUS_EXPIRED = 4;   // 已过期

    /**
     * 获取状态文本
     * @return string
     */
    public function getStatusTextAttribute()
    {
        $statusMap = [
            self::STATUS_UNUSED => '未使用',
            self::STATUS_USED => '已使用',
            self::STATUS_EXPIRED => '已过期'
        ];
        
        return $statusMap[$this->status] ?? '未知状态';
    }

    /**
     * 生成核销码
     * @return string
     */
    public static function generateTicketCode()
    {
        return strtoupper(substr(md5(uniqid(mt_rand(), true)), 0, 8));
    }

    /**
     * 检查核销码是否可用
     * @return bool
     */
    public function isAvailable()
    {
        return $this->status === self::STATUS_UNUSED;
    }

    /**
     * 使用核销码
     * @return bool
     */
    public function use()
    {
        if (!$this->isAvailable()) {
            return false;
        }
        
        $this->status = self::STATUS_USED;
        $this->used_at = time();
        $this->updated_at = time();
        
        return $this->save();
    }

    /**
     * 过期核销码
     * @return bool
     */
    public function expire()
    {
        $this->status = self::STATUS_EXPIRED;
        $this->updated_at = time();
        
        return $this->save();
    }

        /**
     * 生成核销码
     * 
     * @param BizGoodsOrderModel $order 订单对象
     * @return array 生成的核销码数组
     * @throws \Exception
     */
    public static function generateTickets(BizGoodsOrderModel $order): array
    {
        $quantity = $order->quantity ?? 1;
        $tickets = [];
        
        // 批量生成核销码，提高性能
        $codes = self::generateUniqueCodes($quantity);
        
        $currentTime = time();
        $expiredAt = $currentTime + (30 * 24 * 3600); // 30天后过期
        
        for ($i = 0; $i < $quantity; $i++) {
            $ticket = new self();
            $ticket->goods_id = $order->biz_goods_id;
            $ticket->biz_id = $order->biz_id;
            $ticket->user_id = $order->user_id;
            $ticket->order_id = $order->id;
            $ticket->code = $codes[$i];
            $ticket->status = 0; // 未使用
            $ticket->created_at = $currentTime;
            $ticket->expired_at = $expiredAt;
            $ticket->updated_at = $currentTime;
            $ticket->money = round($order->pay_money / $quantity, 2);
            
            $tickets[] = $ticket;
        }
        
        return $tickets;
    }
    
    /**
     * 生成唯一的核销码
     * 
     * @param int $count 需要生成的数量
     * @param int $length 核销码长度，默认9位
     * @return array 核销码数组
     * @throws \Exception
     */
    private static function generateUniqueCodes(int $count, int $length = 9): array
    {
        $codes = [];
        $maxAttempts = 1000; // 最大尝试次数，防止无限循环
        $attempts = 0;
        
        // 字符集：数字和大写字母，排除容易混淆的字符
        $chars = '23456789ABCDEFGHJKLMNPQRSTUVWXYZ';
        $charsLength = strlen($chars);
        
        while (count($codes) < $count && $attempts < $maxAttempts) {
            $code = '';
            
            // 生成随机核销码
            for ($i = 0; $i < $length; $i++) {
                $code .= $chars[random_int(0, $charsLength - 1)];
            }
            
            // 检查是否已存在
            if (!in_array($code, $codes) && !self::codeExists($code)) {
                $codes[] = $code;
            }
            
            $attempts++;
        }
        
        if (count($codes) < $count) {
            throw new \Exception('无法生成足够的唯一核销码，请重试');
        }
        
        return $codes;
    }
    
    /**
     * 检查核销码是否已存在
     * 
     * @param string $code 核销码
     * @return bool
     */
    private static function codeExists(string $code): bool
    {
        return self::where('code', $code)->exists();
    }
    
    /**
     * 批量保存核销码
     * 
     * @param array $tickets 核销码数组
     * @return bool
     */
    public static function batchSaveTickets(array $tickets): bool
    {
        try {
            // 使用事务确保数据一致性
            \support\Db::transaction(function () use ($tickets) {
                foreach ($tickets as $ticket) {
                    $ticket->save();
                }
            });
            
            return true;
        } catch (\Exception $e) {
            // 记录错误日志
            \support\Log::error('批量保存核销码失败: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * 关联商家商品
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function bizGoods()
    {
        return $this->belongsTo(BizGoodsModel::class, 'goods_id', 'id');
    }

    /**
     * 关联用户
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function user()
    {
        return $this->belongsTo(UserModel::class, 'user_id', 'id');
    }

    /**
     * 关联商家
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function biz()
    {
        return $this->belongsTo(BizModel::class, 'biz_id', 'id');
    }

    public function safeCode(){
        return  mb_strlen($this->code) > 4 
        ? mb_substr($this->code, 0, 2) . str_repeat('*', mb_strlen($this->code) - 4) . mb_substr($this->code, -2) 
        : $this->code;
    }
} 